// 放大镜的类
/*
  盒子名称
    => show: 承载展示图片的盒子, 内部有一个 img 标签是展示图片
    => mask: 图片上的遮罩层盒子
    => enlarge: 右边的放大盒子, 内部有一个 img 标签是放大图片
    => list: 是列表盒子, 内部有多个 img 标签用作切换图片使用
*/
/*
  分析要做的事情:
    1. 调整比例
      => 调整 mask 和 show  以及  enlarge 和 内部 img 的尺寸
      => 四个任意调整一个, 让其成比例
      => 可以手动计算, 然后设置 css
      => 可以使用 js 操作
    2. 移入移出
      => 移入 show 盒子的时候, 显示 mask 和 enlarge
      => 移出 show 盒子的时候, 隐藏 mask 和 enlarge
    3. 列表切换
      => 点击 list 内的每一个 img 的时候
      => 能对应切换 show 内 img 的 src
      => 能对应切换 enlarge 内 img 的 src
      => 对应 list 内 img 类名的切换
    4. 移动联动
      => 当鼠标在 show 盒子内移动的时候
      => mask 跟随鼠标实时移动
      => enlerge 盒子内的 img 按照比例跟随移动

  分析类需要的属性和方法
    + 属性:
      => 范围元素 .box
      => show 盒子
      => mask 盒子
      => enlarge 盒子
      => list 盒子
      => mask 尺寸
      => show 尺寸
      => enlarge 内图片的尺寸
    + 方法:
      => 1. 调整比例
      => 2. 移入移出
      => 3. 列表切换
      => 4. 移动联动
    + 我们将来使用 Enlarge 类创建的对象
      => 要包含以上属性(书写在 constructor 内)
      => 要能调用以上方法(书写在 原型上的方法)
*/


class Enlarge {
  constructor (select) {
    // 范围元素
    this.ele = document.querySelector(select)
    // 各种元素
    this.show = this.ele.querySelector('.show')
    this.mask = this.ele.querySelector('.mask')
    this.list = this.ele.querySelector('.list')
    this.enlarge = this.ele.querySelector('.enlarge')
    // 各种尺寸
    this.show_w = this.show.clientWidth
    this.show_h = this.show.clientHeight
    // 注意, 打开页面的时候, 你的 mask 盒子是默认隐藏的
    // offset 一组和 client 一组 都是不能获取到 隐藏状态的尺寸
    // 应该使用获取非行内样式
    this.mask_w = parseInt(window.getComputedStyle(this.mask).width)
    this.mask_h = parseInt(window.getComputedStyle(this.mask).height)
    // enlarge 内图片的尺寸同一个道理
    this.bg_w = parseInt(window.getComputedStyle(this.enlarge.firstElementChild).width)
    this.bg_h = parseInt(window.getComputedStyle(this.enlarge.firstElementChild).height)

    // 利用 this 去把这些方法直接调用
    this.setScale()
    this.overOut()
    this.listChange()
    this.move()
  }

  // 1. 调整比例
  /*
      mask 尺寸      enlarge 尺寸
    ------------ = --------------
      show 尺寸         bg 尺寸
    enlarge 尺寸 * show 尺寸 = mask 尺寸 * bg 尺寸
    enlarge 尺寸 = mask 尺寸 * bg 尺寸 / show 尺寸
  */
  setScale () {
    // 1. 计算尺寸
    this.enlarge_w = this.mask_w * this.bg_w / this.show_w
    this.enlarge_h = this.mask_h * this.bg_h / this.show_h

    // 2. 给 this.enlarge 盒子进行赋值
    this.enlarge.style.width = this.enlarge_w + 'px'
    this.enlarge.style.height = this.enlarge_h + 'px'
  }

  // 2. 移入移出
  overOut () {
    // 2-1. 移入 show 对应的 mash 和 enlarge 显示
    this.show.addEventListener('mouseover', () => {
      this.mask.style.display = 'block'
      this.enlarge.style.display = 'block'
    })

    // 2-2. 移出 show 对应的 mask 和 enlarge 隐藏
    this.show.addEventListener('mouseout', () => {
      this.mask.style.display = 'none'
      this.enlarge.style.display = 'none'
    })
  }

  // 3. 列表切换
  /*
    3-1. 切换对应 img 标签的类名
      => 完全就是选项卡的逻辑
      => 所有 img 都没有类名
      => 给点击的这个添加上类名
    3-2. 切换对应位置的图片地址
      => 我怎么知道切换成哪一个图片地址呢 ?
      => 我们可以提前把需要用到的地址以自定义属性的形式书写在 img 标签身上
      => 当你点击的时候, 拿到自定义属性就可以有地址了
  */
  listChange () {
    this.list.addEventListener('click', e => {
      e = e || window.event
      const target = e.target || e.srcElement

      // 判断点击的是 img 标签
      if (target.nodeName !== 'IMG') return

      // 代码能来到这里, 表示你点击的是 img 标签
      // 3-1. 切换类名
      for (let i = 0; i < this.list.children.length; i++) {
        this.list.children[i].classList.remove('active')
      }
      target.classList.add('active')

      // 3-2. 切换图片
      const showUrl = target.dataset.show
      const enlargeUrl = target.dataset.enlarge
      // 进行对应的切换
      this.show.firstElementChild.src = showUrl
      this.enlarge.firstElementChild.src = enlargeUrl
    })
  }

  // 4. 移动联动
  /*
    问题: 坐标使用哪一组 ?
      => client 一组: 相对于浏览器可视窗口左上角
      => page 一组: 相对于页面文档流左上角
      => offset 一组: 相对于事件目标左上角  (选择)
        -> 因为 mask 就是根据 show 盒子进行定位的
        -> 注意: 相对于事件目标, 不是 show 盒子
          + 给 mask 盒子做一个样式穿透, 能直接穿透到下面的 show 盒子身上
    问题: 如何计算右侧放大图片的移动尺寸 ?
      mask 移动距离       mask 尺寸
    --------------- = --------------
      放大图移动距离      enlarge 尺寸
    放大图移动距离 * mask 尺寸 = mask 移动距离 * enlarge 尺寸
    放大图移动距离 = mask 移动距离 * enlarge 尺寸 / mask 尺寸
  */
  move () {
    // 4-1. 给 show 盒子绑定鼠标移动事件
    this.show.addEventListener('mousemove', e => {
      e = e || window.event

      // 4-2. 拿到坐标
      let x = e.offsetX - this.mask_w / 2
      let y = e.offsetY - this.mask_h / 2

      // 4-3. 进行边界值判断
      if (x <= 0) x = 0
      if (y <= 0) y = 0
      if (x >= this.show_w - this.mask_w) x = this.show_w - this.mask_w
      if (y >= this.show_h - this.mask_h) y = this.show_h - this.mask_h

      // 4-4. 给 mask 盒子赋值
      this.mask.style.left = x + 'px'
      this.mask.style.top = y + 'px'

      // 4-5. 计算出一个右侧盒子应该移动的尺寸
      // 放大图移动距离 = mask 移动距离 * enlarge 尺寸 / mask 尺寸
      const bg_x = x * this.enlarge_w / this.mask_w * -1
      const bg_y = y * this.enlarge_h / this.mask_h * -1

      // 4-6. 给右侧的 enlarge 下的 img 标签赋值
      this.enlarge.firstElementChild.style.left = bg_x + 'px'
      this.enlarge.firstElementChild.style.top = bg_y + 'px'
    })
  }
}
